/**
 * 
 */
package it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats;

import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;


/**
 * @author Massimo Canonaco
 *
 */
public class StatsFactory {
	
	/** */

	protected StartingRoleFileFactory builder;
	
	/** */
	protected HashMap<String, StartingRole> base;

	/** */
	protected final String FOLDER;
	
	/** */
	public StatsFactory(final StartingRoleFileFactory fileManager, final String path)
	{
		builder = fileManager;
		FOLDER = path;
	}
	
	public void loadAllRoles(){
		File folder = new File(FOLDER);

		for(File file : folder.listFiles())
			if(file.isFile()){
			    String roleName = file.getName();
			    int dot = roleName.lastIndexOf(".");
			    load(roleName.substring(0,dot));
			}
		
	}
	
	public Set<String> getRoleNames(){
		return base.keySet();
	}
	
	/** */
	private void load(final String race)
	{
		if(base == null)
		{
			base = new HashMap<>();
		}

		if(!base.containsKey(race))
		{
			base.put(race, builder.load(FOLDER,race));
		}
	}
	
	/** */
	public StartingRole getBaseStats(final String name)
	{
		load(name);
		return base.get(name);
	}
	
	/** Basic idea to levelling the statistics of the 'role' R is:
		 1. Get the basic values from the prototype A.<br/>
		 2. Copy to R the "perLevel" values and then multiply them per the character level.<br/>
		 3. Finally sum the base values of the role.<br/>
		It's the same procedure with abilities.
	*/
	public boolean levellingRole(final Role role, final int level)
	{
		final String race = role.getName();

			// Load the values for that race into our prototype
			load(race);

			// Load base stats for the given role
			StartingRole basePrototype = base.get(race);
			// Make a copy of the "per level" stats
			role.characteristics.copy(basePrototype.getPerLevelCharacteristics());
			
			// Multiply "per level" stats by the character level and then add a base amount
			role.characteristics.multiply(level).sum(basePrototype.characteristics, true);

			for(int index = 0; index < basePrototype.abilities.size(); index++) {
			
				role.abilities.add(new AbilityStats());
				AbilityStats ability = role.abilities.get(index);
				AbilityStats prototypeAbility = basePrototype.abilities.get(index);
				
				// Immutables so it's ok to set instead of copying
				ability.setAbilityValue(prototypeAbility.getAbilityValue());
				ability.setScalingAbilities(prototypeAbility.getScalingAbilities());
				
				ability.copy(basePrototype.getPerLevelAbilities().get(index));
				ability.multiply(level).sum(prototypeAbility, true);
			
			}
			
			// The requested race was valid
			return true;
	}
	
	/**@see it.unical.canonaco.rende.igpe.game.cbv.logiclayer.engine.component.pawn.stats.StatsFactory#levellingRole(..).
	 * @return A new role with his levelled statistics. An empty role is returned if the request is invalid.  */
	public Role levellingRole(final String roleName, final int level)
	{
			Role role = new Role();

			// Load the values for that race into our prototype
			load(roleName);
			
			// Load base stats for the given role
			StartingRole basePrototype = base.get(roleName);
			
			// Copy the name
			role.setName(basePrototype.getName());
			
			// Make a copy of the "per level" stats
			role.characteristics.copy(basePrototype.getPerLevelCharacteristics());
			// Multiply "per level" stats by the character level and then add a base amount
			role.characteristics.multiply(level).sum(basePrototype.characteristics, true);
			
			for(int index = 0; index < basePrototype.abilities.size(); index++) {
				
				role.abilities.add(new AbilityStats());
				AbilityStats ability = role.abilities.get(index);
				AbilityStats prototypeAbility = basePrototype.abilities.get(index);
				
				// Immutables so it's ok to set instead of copying
				ability.setAbilityValue(prototypeAbility.getAbilityValue());
				ability.setScalingAbilities(prototypeAbility.getScalingAbilities());
				
				ability.copy(basePrototype.getPerLevelAbilities().get(index));
				ability.multiply(level).sum(prototypeAbility, true);
			}
			
			// The requested race was valid
			return role;
	}
}
